#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import locale
import os
import shutil
import time

from oracle import logger
from common.file_common import delete_file
from common.common import read_result_file
from oracle.common.common import shutdown_database_abort
from oracle.common.windows_common import write_tmp_file, execute_windows_cmd, create_dir, set_db_silence_sql, \
    execute_windows_sqlplus_cmd, check_path_in_disk_group, execute_windows_rman_cmd, find_content_in_file, \
    get_online_redo_log_info
from oracle.common.constants import ScriptExitCode, PluginPathConstant, RETURN_INVALID, OracleStartTypeEnum
from oracle.services.restore.windows_sbin_func import start_open, get_temp_file_info


def check_dg_exit(pid, recover_path: str, recover_target: str, additional_path: str, params):
    oracle_home = params['oracle_home']
    asm_instance = params['asm_sid_name']
    logger.debug(f"Enter function check_dg_exit, pid:{pid}.")
    if (not recover_path) or (recover_target != "1"):
        return ScriptExitCode.SUCCESS

    dg_list = []
    additional_dbfiles_path = os.path.join(additional_path, "dbfiles")
    dg_list = get_dg_name_from_file(additional_dbfiles_path, 3, dg_list)

    additional_ctrlfiles_path = os.path.join(additional_path, "ctrlfiles")
    dg_list = get_dg_name_from_file(additional_ctrlfiles_path, 0, dg_list)

    additional_logfiles_path = os.path.join(additional_path, "logfiles")
    dg_list = get_dg_name_from_file(additional_logfiles_path, 1, dg_list)

    if not dg_list:
        return ScriptExitCode.SUCCESS

    logger.debug(f"Begin check dg list, pid:{pid}")
    for dg_name in dg_list:
        dg_name = dg_name[1:]
        ret = check_path_in_disk_group(pid, dg_name, asm_instance, oracle_home)
        if not ret:
            logger.error(f"Diskgroup {dg_name} does not exist or is not mounted, pid:{pid}")
            return ScriptExitCode.ERROR_ORACLE_ASM_DISKGROUP_NOTMOUNT
    return ScriptExitCode.SUCCESS


def get_dg_name_from_file(file_name, site, dg_list):
    encoding = locale.getdefaultlocale()[1]
    file_lines = read_result_file(file_name, encoding=encoding).splitlines()
    for line in file_lines:
        dbf_full_path = line.split(";")[site]
        if dbf_full_path[0] != "+":
            continue
        dg_name = dbf_full_path.split("/")[0]
        if dg_name not in dg_list:
            dg_list.append(dg_name)
    return dg_list


def create_dirs_from_file(pid, files, asm_instance, oracle_home):
    logger.debug(f"Creating dirs from file ({files}), pid:{pid}.")
    encoding = locale.getdefaultlocale()[1]
    files_content = read_result_file(files, encoding=encoding)
    files_content_lines = files_content.splitlines()
    new_lines = []
    for line in files_content_lines:
        # 以斜杠为分隔符分割字符串，并去掉最后一个元素
        parts = line.split("\\")[:-1]
        # 以斜杠为连接符连接列表，并以分号为分隔符分割字符串，取最后一个元素
        new_line = "\\".join(parts).split(";")[-1]
        new_lines.append(new_line)
    new_lines = sorted(set(new_lines))
    for line in new_lines:
        create_dir(pid, line, asm_instance, oracle_home)


def delete_spfile(pid, instance_name, oracle_home):
    logger.debug(f"Enter function delete_spfile, pid:{pid}.")
    file = os.path.join(oracle_home, f"dbs\\spfile{instance_name}.ora")
    if os.path.exists(file):
        logger.debug(f"start delete spfile {file}, pid:{pid}")
        if os.access(file, os.R_OK):
            delete_file(file)
            logger.info(f"Remove Spfile {file} success, pid:{pid}.")
        else:
            logger.info(f"Remove Spfile fail, pid:{pid}.")
    else:
        logger.info(f"No Find spfile, pid:{pid}.")


def create_pfile_from_pm(pid, pfile_pid, main_backup_path, db_name, pfile_name):
    logger.debug(f"Enter function create_pfile_from_pm, pid:{pid}.")
    if not pfile_pid:
        backup_pfile = os.path.join(main_backup_path, f"ebackup-{db_name}-pfile.ora")
        if not os.path.exists(backup_pfile):
            logger.error(f"Copy path pfile {backup_pfile} is not exist can not restore, pid:{pid}")
            return RETURN_INVALID
        try:
            shutil.copy(backup_pfile, pfile_name)
        except Exception as exception:
            logger.error(f"Copy path pfile to oracle home failed can not restore, exception={exception}, pid={pid}.")
            return RETURN_INVALID
        logger.info(f"Copy pfile from {backup_pfile} to {pfile_name} success, pid:{pid}")
    else:
        user_pfile = f"{PluginPathConstant.WINDOWS_TMP_PATH}/pfile{pfile_pid}"
        if not os.path.exists(user_pfile):
            logger.error(f"From pm pfile {user_pfile} is not exit can not restore, pid:{pid}.")
            return RETURN_INVALID
        logger.info(f"Create pfile from user pfile pfile{pfile_pid}, pid:{pid}")
        if os.access(pfile_name, os.R_OK):
            delete_file(pfile_name)
            logger.info(f"Remove pfile {pfile_name} success, pid:{pid}.")
        else:
            logger.info(f"Remove Spfile fail, pid:{pid}.")
        try:
            shutil.copy(user_pfile, pfile_name)
        except Exception as exception:
            logger.error(f"Create pfile from user pfile fail, exception={exception}, pid={pid}.")
            return RETURN_INVALID
        logger.info(f"Create pfile from user pfile success, pid:{pid}.")
        if os.access(user_pfile, os.R_OK):
            delete_file(user_pfile)
            logger.info(f"Remove pfile {user_pfile} success, pid:{pid}.")
        else:
            logger.info(f"Remove pfile fail, pid:{pid}.")
    return ScriptExitCode.SUCCESS


def replace_pfile_env_by_newenv(pid, additional, pfile_name, in_oracle_home, in_oracle_base):
    logger.debug(f"Begin to replace oracle home and oracle base env value, pid:{pid}")
    encoding = locale.getdefaultlocale()[1]
    env_file_content = read_result_file(f"{additional}\\env_file", encoding=encoding)
    env_file_content_lines = env_file_content.splitlines()
    backup_ora_base_path = ''
    backup_ora_home_path = ''
    for line in env_file_content_lines:
        line = line.strip()
        if line.startswith("ORACLE_BASE="):
            backup_ora_base_path = line.split('=')[1]
        elif line.startswith("ORACLE_HOME="):
            backup_ora_home_path = line.split('=')[1]

    # replace oracle home path
    ret_code = replace_content_in_file(pfile_name, backup_ora_home_path, in_oracle_home)
    if ret_code != ScriptExitCode.SUCCESS:
        logger.error(f"Replace pfile oracle home path failed, pid:{pid}.")
        return ret_code
    # replace oracle base path
    ret_code = replace_content_in_file(pfile_name, backup_ora_base_path, in_oracle_base)
    if ret_code != ScriptExitCode.SUCCESS:
        logger.error(f"Replace pfile oracle base path failed, pid:{pid}.")
        return ret_code
    logger.info(f"Replace pfile oracle path success, pid:{pid}.")
    return ScriptExitCode.SUCCESS


def replace_content_in_file(file, origin_content, target_content):
    encoding = locale.getdefaultlocale()[1]
    pfile_name_content = read_result_file(file, encoding=encoding)
    replace_content = pfile_name_content.replace(origin_content, target_content)
    tmp_file = f"{file}.bak"
    write_tmp_file(tmp_file, replace_content)
    try:
        delete_file(file)
        os.rename(tmp_file, file)
    except Exception as exception:
        logger.error(f"Replace {origin_content} to {target_content} failed, exception={exception}.")
        return RETURN_INVALID
    return ScriptExitCode.SUCCESS


def create_db_config_dir(pid, pfile_path, db_name, asm_instance, oracle_home):
    # restriction
    # 1. asm instance       ASMSIDNAME
    logger.debug(f"Begin to prepare DB env, pid:{pid}.")
    encoding = locale.getdefaultlocale()[1]
    pfile_lines = read_result_file(pfile_path, encoding=encoding).splitlines()
    audit_file_dest_line = ''
    diagnostic_dest_line = ''
    db_recovery_file_dest_line = ''
    for line in pfile_lines:
        if "audit_file_dest=" in line:
            audit_file_dest_line = line
        if "diagnostic_dest=" in line:
            diagnostic_dest_line = line
        if "db_recovery_file_dest=" in line:
            db_recovery_file_dest_line = line
    if audit_file_dest_line:
        adump_dir = audit_file_dest_line.split("'")[1]
        create_dir(pid, adump_dir, asm_instance, oracle_home)
    if diagnostic_dest_line:
        diag_dir = diagnostic_dest_line.split("'")[1]
        create_dir(pid, diag_dir, asm_instance, oracle_home)
    if not db_recovery_file_dest_line:
        logger.info(f"no recovery, create db config dir success, pid:{pid}")
        return ScriptExitCode.SUCCESS
    recover_dest = db_recovery_file_dest_line.split("'")[1]
    create_dir(pid, recover_dest, asm_instance, oracle_home)
    # create archive dest  and   set owner
    db_name = db_name.upper()
    recover_dest = os.path.join(recover_dest, db_name)
    create_dir(pid, recover_dest, asm_instance, oracle_home)
    logger.info(f"Create db config dir success, pid:{pid}")
    return ScriptExitCode.SUCCESS


def create_spfile_from_pfile(restore_params, spfile_location, addition, pfile_name):
    pid = restore_params['pid']
    instance_name = restore_params['db_instance']
    db_user = restore_params['db_user']
    db_password = restore_params['db_user_pwd']
    db_name = restore_params['db_name']
    asm_instance = restore_params['asm_sid_name']
    oracle_home = restore_params['oracle_home']
    logger.debug(f"Enter function create_spfile_from_pfile, pid:{pid}.")
    encoding = locale.getdefaultlocale()[1]
    if not spfile_location:
        spfile = os.path.join(addition, "spfile")
        if os.path.exists(spfile):
            spfile_content = read_result_file(spfile, encoding=encoding).strip()
            if spfile_content.strip()[0] != "+":
                spfile_location_parts = spfile_content.strip().split("\\")
                spfile_location = "\\".join(spfile_location_parts[:-1])
            else:
                spfile_location_parts = spfile_content.strip().split("/")
                spfile_location = "/".join(spfile_location_parts[:-1])
        else:
            spfile_location = os.path.join(oracle_home, "dbs")
        if not spfile_location:
            logger.error(f"Spfile location path is none can not create spfile, pid:{pid}")
            return RETURN_INVALID
        create_dir(pid, spfile_location, asm_instance, oracle_home)
    lowercase_db_name = db_name.lower()
    spfile_path = os.path.join(spfile_location, f"ebackup-spfile{lowercase_db_name}.ora")
    if os.path.exists(spfile_path):
        logger.warning(f"Location already has the same name spfile "
                       f"[{spfile_location}\\ebackup-spfile{lowercase_db_name}.ora] will delete, pid:{pid}.")
        delete_file(spfile_path)
    logger.debug(f"Begin to create spfile to location {spfile_location}, pid:{pid}.")
    tmp_sql = f"{PluginPathConstant.WINDOWS_TMP_PATH}/create_spfile_from_pfile{pid}.sql"
    tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/create_spfile_from_pfile{pid}.rst"
    tmp_sql_content = f"SPOOL {tmp_rst}\n" \
                      f"CREATE SPFILE='{spfile_location}\\ebackup-spfile{lowercase_db_name}.ora' " \
                      f"FROM PFILE='{pfile_name}';\nSPOOL OFF\nexit;\n"
    write_tmp_file(tmp_sql, tmp_sql_content)
    set_db_silence_sql(tmp_sql)
    params = {"is_silence": 1, "db_user": db_user, "db_password": db_password}
    ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, instance_name)
    if ret_code != ScriptExitCode.SUCCESS:
        logger.error(f"Create spfile failed, ret={ret_code}, error is {read_result_file(tmp_rst, encoding=encoding)}, "
                     f"pid:{pid}.")
    else:
        logger.info(f"Create spfile [{spfile_location}/ebackup-spfile{lowercase_db_name}.ora] succ, pid:{pid}.")
    delete_file(tmp_sql)
    delete_file(tmp_rst)
    return ret_code


def create_init_file(restore_params, spfile_location, addition):
    pid = restore_params['pid']
    db_instance = restore_params['db_instance']
    db_name = restore_params['db_name']
    asm_sid_name = restore_params['asm_sid_name']
    in_oracle_home = restore_params['oracle_home']
    logger.info(f"Enter function create_init_file, pid:{pid}.")
    lower_case_dbname = db_name.lower()
    if not spfile_location:
        spfile_path = os.path.join(addition, "spfile")
        if os.path.exists(spfile_path):
            encoding = locale.getdefaultlocale()[1]
            spfile_path_content = read_result_file(spfile_path, encoding=encoding)
            tmp_str = spfile_path_content.strip()
            if tmp_str[0] != "+":
                spfile_location_parts = tmp_str.split("\\")
                spfile_location = "\\".join(spfile_location_parts[:-1])
            else:
                spfile_location_parts = tmp_str.split("/")
                spfile_location = "/".join(spfile_location_parts[:-1])
        else:
            spfile_location = os.path.join(in_oracle_home, "dbs")
    # 检查首字母是不是盘符
    if spfile_location.split(":")[0].isalpha():
        if not os.path.exists(spfile_location):
            logger.error(
                f"Spfile [{spfile_location}] location is none or spfile is not exit "
                f"cant not creaet init file, pid:{pid}.")
            return RETURN_INVALID
    else:
        ret = check_path_in_disk_group(pid, spfile_location, asm_sid_name, in_oracle_home)
        if not ret:
            logger.error(
                f"Spfile [{spfile_location}] location is none or spfile is not exit "
                f"cant not creaet init file, pid:{pid}.")
            return RETURN_INVALID
    logger.info(
        f"Begin to create oracle init file init{db_instance}.ora, SpfileLocation is {spfile_location}, pid:{pid}.")
    init_file = os.path.join(in_oracle_home, "database", f"init{db_instance}.ora")
    spfile = os.path.join(spfile_location, f"ebackup-spfile{lower_case_dbname}.ora")
    try:
        delete_file(init_file)
        init_file_content = f"SPFILE={spfile}"
        write_tmp_file(init_file, init_file_content)
    except Exception as exception:
        logger.error(f"Create {db_instance} init file error, exception:{exception}, pid:{pid}.")
        return RETURN_INVALID
    logger.info(f"Create {db_instance} init file success, pid:{pid}.")
    return ScriptExitCode.SUCCESS


def build_catalog_datafile_sql(pid, rman_params, restore_sql, backup_path_list, additional):
    logger.info(f"Enter function build_original_restore_database_sql, pid:{pid}.")
    datafile_tmp_sql = f"{PluginPathConstant.WINDOWS_TMP_PATH}/list_datafile_copy_{pid}.sql"
    datafile_tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/list_datafile_copy_{pid}.txt"
    datafile_tmp_sql_content = "list datafilecopy all;\n" \
                               "quit;"
    write_tmp_file(datafile_tmp_sql, datafile_tmp_sql_content)
    enc_type = 0
    ret_code = execute_windows_rman_cmd(pid, rman_params, enc_type, datafile_tmp_sql, datafile_tmp_rst)
    if ret_code != ScriptExitCode.SUCCESS:
        logger.error(f"List datafilecopy all failed, ret_code={ret_code}, pid:{pid}.")
        delete_file(datafile_tmp_sql)
        delete_file(datafile_tmp_rst)
        return ""
    logger.info(f"List datafilecopy success, pid:{pid}.")

    encoding = locale.getdefaultlocale()[1]
    data_file_path = f"{PluginPathConstant.WINDOWS_TMP_PATH}/data_file_path_{pid}.txt"
    data_file_path_content = ""
    datafile_tmp_rst_lines = read_result_file(datafile_tmp_rst, encoding=encoding).splitlines()
    for line in datafile_tmp_rst_lines:
        if line.find("//DATABACKUP") != -1:
            data_file_path_content += f"{line}\n"
    write_tmp_file(data_file_path, data_file_path_content)
    delete_file(datafile_tmp_sql)
    delete_file(datafile_tmp_rst)
    ip_use_info = f"{PluginPathConstant.WINDOWS_TMP_PATH}/ip_use_info_{pid}.txt"
    # sh脚本中将分号替换成空格后遍历
    backup_path_list_arr = backup_path_list.split(";")
    ip_use_info_content = ""
    data_file_path_lines = read_result_file(data_file_path, encoding=encoding).splitlines()
    for data_path in backup_path_list_arr:
        count = 0
        for line in data_file_path_lines:
            if data_path in line:
                count += 1
        ip_use_info_content += f"{data_path}={count}"
    write_tmp_file(ip_use_info, ip_use_info_content)
    dbfiles = os.path.join(additional, "dbfiles")
    dbfiles_lines = read_result_file(dbfiles, encoding=encoding).splitlines()
    for line in dbfiles_lines:
        file_id = line.split(';')[2]
        if not file_id:
            continue
        status = find_content_in_file(fr"\{file_id}\FNO", data_file_path)
        if not status:
            path = find_min_use_path(pid, ip_use_info)
            restore_sql += f"    catalog start with '{path}\{file_id}' noprompt;\n"
    delete_file(data_file_path)
    delete_file(ip_use_info)
    return restore_sql


def find_min_use_path(pid, ip_use_info):
    num = 0
    encoding = locale.getdefaultlocale()[1]
    tmp_ip_use_info = f"{PluginPathConstant.WINDOWS_TMP_PATH}/tmp_txt_{pid}.bak"
    ip_use_info_lines = read_result_file(ip_use_info, encoding=encoding).splitlines()
    path = ""
    for line in ip_use_info_lines:
        if num == 0:
            path = line.split('=')[0]
            num = int(line.split('=')[1])
        else:
            if num > int(line.split('=')[1]):
                path = line.split('=')[0]
                num = int(line.split('=')[1])

    num = num + 1
    tmp_ip_use_info_content = ""
    for line in ip_use_info_lines:
        if path in line:
            continue
        else:
            tmp_ip_use_info_content += f"{line}\n"
    tmp_ip_use_info_content += f"{path}={num}"
    write_tmp_file(tmp_ip_use_info, tmp_ip_use_info_content)
    delete_file(ip_use_info)
    os.rename(tmp_ip_use_info, ip_use_info)
    return path


def build_catalog_sql(tmp_sql, restore_params, resetlogs_id, in_job_list):
    pid = restore_params['pid']
    main_backup_path = restore_params['main_backup_path']
    archive = restore_params['archive']
    backup_path_list = restore_params['backup_path_list']
    additional = restore_params['additional']
    logger.info(f"Enter function build_catalog_sql, pid:{pid}, main_backup_path:{main_backup_path}, archive:{archive}, "
                f"in_job_list:{in_job_list}, backup_path_list:{backup_path_list}.")
    logger.info(f"additional:{additional}")
    tmp_sql += f"    catalog start with '{main_backup_path}\\log' noprompt;\n"
    if os.path.exists(f"{archive}\\resetlogs_id{resetlogs_id}"):
        logger.info(f"Start catalog archive log, {archive}\\resetlogs_id{resetlogs_id}, pid:{pid}.")
        tmp_sql += f"    catalog start with '{archive}\\resetlogs_id{resetlogs_id}' noprompt;\n"
    job_list = in_job_list.split(",")
    for job_id in job_list:
        if not job_id:
            continue
        tmp_sql += f"    catalog start with '{archive}\\{job_id}\\resetlogs_id{resetlogs_id}' noprompt;\n"
    path_num = len(backup_path_list.split(";"))
    index_datafile = 0
    encoding = locale.getdefaultlocale()[1]
    dbfiles_lines = read_result_file(f"{additional}\\dbfiles", encoding=encoding).splitlines()
    backup_path_list_arr = backup_path_list.split(";")
    for line in dbfiles_lines:
        if not line:
            continue
        index_path = index_datafile % path_num
        index_datafile += 1
        file_id = line.split(";")[2]
        path = backup_path_list_arr[index_path]
        tmp_sql += f"    catalog start with '{path}\\{file_id}' noprompt;\n"
    return tmp_sql


def build_newname_datafile_sql(tmp_sql, restore_params, omf_enable):
    pid = restore_params['pid']
    db_name = restore_params['db_name']
    task_type = restore_params['task_type']
    backup_path_list = restore_params['backup_path_list']
    recover_path = restore_params['recover_path']
    asm_instance = restore_params['asm_sid_name']
    oracle_home = restore_params['oracle_home']
    additional = restore_params['additional']
    logger.info(f"Enter function build_newname_datafile_sql, pid:{pid}.")
    upper_db_name = db_name.upper()
    target_path = ""
    if task_type == 0 and recover_path:
        target_path = recover_path
    if task_type == 1 or task_type == 2:
        target_path = backup_path_list.split(";")[0]
    if target_path == "":
        return tmp_sql
    encoding = locale.getdefaultlocale()[1]
    dbfiles_lines = read_result_file(f"{additional}\\dbfiles", encoding=encoding).splitlines()
    for line in dbfiles_lines:
        tablespace_name = line.split(";")[1]
        file_id = line.split(";")[2]
        if task_type == 0 and recover_path:
            if omf_enable == 0:
                tmp_sql += f"    SET NEWNAME FOR DATAFILE {file_id} to '" \
                           f"{target_path}\\FNO-{file_id}_TS-{tablespace_name}.dbf';\n"
            else:
                datafile_path = os.path.join(target_path, upper_db_name, "datafile")
                create_dir(pid, datafile_path, asm_instance, oracle_home)
                tmp_sql += f"    SET NEWNAME FOR DATAFILE {file_id} to " \
                           f"'{target_path}\\{upper_db_name}\\datafile\\FNO-{file_id}_TS-{tablespace_name}.dbf';\n"
        else:
            tmp_sql += f"    SET NEWNAME FOR DATAFILE {file_id} to '{target_path}\\{file_id}\\FNO-{file_id}_TS-" \
                       f"{tablespace_name}.dbf';\n"
    return tmp_sql


def build_rename_log_file(tmp_redo_sql, restore_params, omf_enable):
    pid = restore_params['pid']
    db_name = restore_params['db_name']
    db_instance = restore_params['db_instance']
    db_user = restore_params['db_user']
    recover_path = restore_params['recover_path']
    asm_instance = restore_params['asm_sid_name']
    oracle_home = restore_params['oracle_home']
    db_user_pwd = restore_params['db_user_pwd']
    logger.info(f"Start build rename redo log file sql, pid:{pid}.")
    tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/get_online_log_info_rst_{pid}.txt"
    ret_code = get_online_redo_log_info(pid, db_instance, db_user, db_user_pwd, tmp_rst)
    if ret_code != 0:
        logger.error(f"Get database online log file info failed, pid:{pid}.")
        delete_file(tmp_rst)
        return ret_code, ""
    time_stamp = int(time.time())
    counter = 0
    # 依次处理每一个redo名称
    encoding = locale.getdefaultlocale()[1]
    tmp_rst_lines = read_result_file(tmp_rst, encoding=encoding).splitlines()
    for line in tmp_rst_lines:
        if not line or ("rows selected" in line):
            continue
        redo_file = line.split()[1]
        if recover_path:
            # 指定恢复路径
            upper_db_name = db_name.upper()
            # 开启OMF则构造路径
            tmp_path = ""
            if omf_enable == 1:
                tmp_path = os.path.join(recover_path, upper_db_name)
            src_path = line.split()[1]
            if omf_enable == 1:
                create_dir(pid, f"{tmp_path}\\onlinelog", asm_instance, oracle_home)
                dst_path = f"{tmp_path}\\onlinelog\\restore-redo-{counter}"
            else:
                dst_path = f"{recover_path}\\restore-redo-{counter}"
            tmp_redo_sql += f"     ALTER DATABASE RENAME FILE '{src_path}' to '{dst_path}-{time_stamp}';\n"
        else:
            # 不指定恢复路径,直接在原目录下新增
            redo_file_parts = redo_file.split("\\")
            # 以斜杠为连接符连接列表，并以分号为分隔符分割字符串，取最后一个元素
            redo_file_dir = "\\".join(redo_file_parts[:-1])
            redo_file_path = f"{redo_file_dir}\\"
            tmp_redo_sql += f"     ALTER DATABASE RENAME FILE '{redo_file}' to '{redo_file_path}-{time_stamp}';\n"
        counter += 1
    delete_file(tmp_rst)
    return ScriptExitCode.SUCCESS, tmp_redo_sql


def build_rename_log_file_for_standby(tmp_redo_sql, restore_params, database_role, exec_by_rman, omf_enable):
    pid = restore_params['pid']
    db_name = restore_params['db_name']
    db_instance = restore_params['db_instance']
    db_user = restore_params['db_user']
    recover_path = restore_params['recover_path']
    asm_instance = restore_params['asm_sid_name']
    oracle_home = restore_params['oracle_home']
    db_user_pwd = restore_params['db_user_pwd']
    logger.info(f"Start build rename redo log file sql for standby, pid:{pid}.")
    tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/get_online_log_info_rst_{pid}.txt"
    ret_code = get_online_redo_log_info(pid, db_instance, db_user, db_user_pwd, tmp_rst)
    if ret_code != 0:
        logger.error(f"Get database online log file info failed, pid:{pid}.")
        delete_file(tmp_rst)
        return ret_code, ""

    if database_role != "PRIMARY":
        if exec_by_rman == "rman":
            tmp_redo_sql += f"sql \"alter system set standby_file_management=''MANUAL''\";\n"
        else:
            tmp_redo_sql += f"alter system set standby_file_management='MANUAL';\n"
    time_stamp = int(time.time())
    counter = 0
    # 依次处理每一个redo名称
    encoding = locale.getdefaultlocale()[1]
    tmp_rst_lines = read_result_file(tmp_rst, encoding=encoding).splitlines()
    for line in tmp_rst_lines:
        if not line or ("rows selected" in line):
            continue
        redo_file = line.split()[1]
        if recover_path:
            # 指定恢复路径
            upper_db_name = db_name.upper()
            # 开启OMF则构造路径
            tmp_path = ""
            if omf_enable == 1:
                tmp_path = os.path.join(recover_path, upper_db_name)
            src_path = line.split()[1]
            if omf_enable == 1:
                create_dir(pid, f"{tmp_path}\\onlinelog", asm_instance, oracle_home)
                dst_path = f"{tmp_path}\\onlinelog\\restore-redo-{counter}"
            else:
                dst_path = f"{recover_path}\\restore-redo-{counter}"
            tmp_redo_sql += f"     ALTER DATABASE RENAME FILE '{src_path}' to '{dst_path}-{time_stamp}';\n"
        else:
            # 不指定恢复路径,直接在原目录下新增
            redo_file_parts = redo_file.split("\\")
            # 以斜杠为连接符连接列表，并以分号为分隔符分割字符串，取最后一个元素
            redo_file_dir = "\\".join(redo_file_parts[:-1])
            redo_file_path = f"{redo_file_dir}\\"
            tmp_redo_sql += f"     ALTER DATABASE RENAME FILE '{redo_file}' to '{redo_file_path}-{time_stamp}';\n"
        counter += 1
    delete_file(tmp_rst)
    return ScriptExitCode.SUCCESS, tmp_redo_sql


def build_rename_datafile_sql(tmp_sql, restore_params, omf_enable, ora_preversion):
    db_name = restore_params['db_name']
    task_type = restore_params['task_type']
    backup_path_list = restore_params['backup_path_list']
    recover_path = restore_params['recover_path']
    additional = restore_params['additional']
    logger.info(f"Enter function build_rename_datafile_sql.")
    upper_db_name = db_name.upper()
    target_path = ""
    if task_type == 0 and recover_path:
        target_path = recover_path
    if task_type == 1 or task_type == 2:
        target_path = backup_path_list.split(";")[0]
    if target_path == "":
        return tmp_sql
    if int(ora_preversion) > 11:
        encoding = locale.getdefaultlocale()[1]
        dbfiles_lines = read_result_file(f"{additional}\\dbfiles", encoding=encoding).splitlines()
        for line in dbfiles_lines:
            tablespace_name = line.split(";")[1]
            file_id = line.split(";")[2]
            src_path = line.split(";")[3]
            if task_type == 0 and recover_path:
                if omf_enable == 0:
                    target_name = f"{target_path}\\FNO-{file_id}_TS-{tablespace_name}.dbf"
                else:
                    target_name = f"{target_path}\\{upper_db_name}\\datafile\\FNO-{file_id}_TS-{tablespace_name}.dbf"
            else:
                target_name = f"{target_path}\\{file_id}\\FNO-{file_id}_TS-{tablespace_name}.dbf"
            if src_path.replace('\\', '/').upper() != target_name.replace('\\', '/').upper():
                tmp_sql += f"    ALTER DATABASE RENAME FILE '{src_path}' to '{target_name}';\n"
        tmp_sql += "    SWITCH DATAFILE ALL;\n"
    else:
        tmp_sql += "    SWITCH DATAFILE ALL;\n"
    return tmp_sql


def build_rename_temp_file_sql(temp_file_sql, restore_params, omf_enable, ora_preversion):
    pid = restore_params['pid']
    db_name = restore_params['db_name']
    db_instance = restore_params['db_instance']
    db_user = restore_params['db_user']
    recover_path = restore_params['recover_path']
    asm_instance = restore_params['asm_sid_name']
    oracle_home = restore_params['oracle_home']
    db_user_pwd = restore_params['db_user_pwd']
    logger.info(f"Start build rename temp file sql, pid:{pid}.")
    tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/get_temp_file_info_rst_{pid}.txt"
    ret_code = get_temp_file_info(pid, db_instance, db_user, db_user_pwd, tmp_rst)
    if ret_code != 0:
        logger.error(f"Get database online log file info failed, pid:{pid}.")
        delete_file(tmp_rst)
        return temp_file_sql

    time_stamp = int(time.time())
    counter = 1
    # 依次处理每一个临时文件名称
    encoding = locale.getdefaultlocale()[1]
    tmp_rst_lines = read_result_file(tmp_rst, encoding=encoding).splitlines()
    for line in tmp_rst_lines:
        if not line or ("rows selected" in line):
            continue
        # 指定恢复路径
        upper_db_name = db_name.upper()
        # 开启OMF则构造路径
        if omf_enable == 1:
            tmp_path = os.path.join(recover_path, upper_db_name)
            create_dir(pid, f"{tmp_path}\\tempfile", asm_instance, oracle_home)
            dst_path = f"{tmp_path}\\tempfile\\temp-{counter}"
        else:
            dst_path = f"{recover_path}\\temp-{counter}"
        if int(ora_preversion) > 11:
            src_path = line.split()[1]
            temp_file_sql += f"     ALTER DATABASE RENAME FILE '{src_path}' to '{dst_path}-{time_stamp}.dbf';\n"
        else:
            file_id = line.split()[0]
            temp_file_sql += f"     SET NEWNAME FOR TEMPFILE {file_id} to '{dst_path}-{time_stamp}.dbf';\n"
        counter += 1
    if int(ora_preversion) <= 11:
        temp_file_sql += "    SWITCH TEMPFILE ALL;\n"
    delete_file(tmp_rst)
    return temp_file_sql


def disable_database_bct(pid, instance_name, upgrade, params, is_start_db=None):
    logger.info(f"Enter function disable_database_bct, pid:{pid}.")
    tmp_sql = f"{PluginPathConstant.WINDOWS_TMP_PATH}/disable_bct_{pid}.sql"
    tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/disable_bct_{pid}.rst"
    # 写输入文件
    content = f"SPOOL {tmp_rst}\n" \
              f"select status from v$block_change_tracking;\n" \
              f"SPOOL OFF\n" \
              f"exit;"
    write_tmp_file(tmp_sql, content)
    set_db_silence_sql(tmp_sql)

    # 执行命令查询bct_status和数据库角色
    ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, instance_name)
    encoding = locale.getdefaultlocale()[1]
    # 读取bct_status
    if ret_code != ScriptExitCode.SUCCESS:
        logger.info(f"Bct status is open before restore. pid:{pid}")
        bct_status = "ENABLED"
    else:
        content = read_result_file(tmp_rst, encoding=encoding)
        bct_status = content.splitlines()[0].strip()
    logger.info(f"Get bct_status SUCCESS! bct_status={bct_status}, pid:{pid}.")
    delete_file(tmp_sql)
    delete_file(tmp_rst)

    content = f"SPOOL {tmp_rst}\n" \
              f"select database_role from v$database;\n" \
              f"SPOOL OFF\n" \
              f"exit;"
    write_tmp_file(tmp_sql, content)
    set_db_silence_sql(tmp_sql)
    ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, instance_name)
    if ret_code != ScriptExitCode.SUCCESS:
        logger.error(
            f"Query database role failed, pid:{pid}, ret_code={ret_code}, "
            f"error is {read_result_file(tmp_rst, encoding=encoding)}")
        delete_file(tmp_sql)
        delete_file(tmp_rst)
        return ret_code

    # 读取database_role
    content = read_result_file(tmp_rst, encoding=encoding)
    database_role = content.splitlines()[0].strip()
    logger.info(f"Get database role SUCCESS! database_role={database_role}")
    delete_file(tmp_sql)
    delete_file(tmp_rst)

    logger.info(f"Begin to open database, DATABASE_ROLE={database_role}, pid:{pid}")
    content = f"SPOOL {tmp_rst}\n"
    if bct_status != "DISABLED":
        content += "alter database disable BLOCK CHANGE TRACKING;\n"
    if is_start_db != str(OracleStartTypeEnum.NOT_START_DB.value):
        if upgrade == 1:
            content += "ALTER DATABASE OPEN RESETLOGS UPGRADE;\n"
        else:
            if database_role != "PRIMARY":
                content += "ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;\n"
                content += "alter database open;\n"
            else:
                content += "ALTER DATABASE OPEN RESETLOGS;\n"
    content += f"SPOOL OFF\n"
    content += "exit;"
    write_tmp_file(tmp_sql, content)
    set_db_silence_sql(tmp_sql)
    logger.info(f"Begin to open database resetlogs, BCT_STATUS={bct_status}, pid:{pid}")
    ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, instance_name)
    if ret_code != ScriptExitCode.SUCCESS:
        logger.error(
            f"Open resetlogs database failed, pid:{pid}, ret_code={ret_code}, "
            f"error is {read_result_file(tmp_rst, encoding=encoding)}")
        delete_file(tmp_sql)
        delete_file(tmp_rst)
        return ret_code
    if is_start_db != str(OracleStartTypeEnum.NOT_START_DB.value):
        logger.info(f"Open resetlogs database success, pid:{pid}.")
    else:
        logger.info(f"No need to open resetlogs database, disable BCT success, pid:{pid}.")
    delete_file(tmp_sql)
    delete_file(tmp_rst)
    return ScriptExitCode.SUCCESS


def enable_bct_after_restore(pid, instance_name, bct_status, pfile_name, restore_params):
    logger.info(f"Start to enable bct! pid = {pid}")
    if bct_status == "true":
        tmp_sql = f"{PluginPathConstant.WINDOWS_TMP_PATH}/temp_enable_bct_{pid}.sql"
        tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/temp_enable_bct_{pid}.rst"
        omf_enable = get_omf_enable(pfile_name)
        if omf_enable == 1:
            sql = f"alter database enable BLOCK CHANGE TRACKING;\n"
        else:
            recover_path = restore_params['recover_path']
            # 开启OMF则构造路径
            time_stamp = int(time.time())
            dst_path = get_des_path(pid, restore_params)
            if not dst_path:
                return RETURN_INVALID
            sql = f"alter database enable BLOCK CHANGE TRACKING using file '{dst_path}-{time_stamp}.log' reuse;\n"
        logger.info(f"sql:{sql}")
        content = f"SPOOL {tmp_rst}\n" \
                  f"{sql}" \
                  f"SPOOL OFF\n" \
                  f"exit;"
        write_tmp_file(tmp_sql, content)
        set_db_silence_sql(tmp_sql)
        params = {
            "is_silence": 1,
            "db_user": restore_params["db_user"],
            "db_password": restore_params["db_user_pwd"]
        }
        ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, instance_name)
        if ret_code != ScriptExitCode.SUCCESS:
            encoding = locale.getdefaultlocale()[1]
            logger.error(f"Enable bct failed, ret = {ret_code}, error: {read_result_file(tmp_rst, encoding=encoding)}")
            delete_file(tmp_sql)
            delete_file(tmp_rst)
            return ret_code
        delete_file(tmp_sql)
        delete_file(tmp_rst)
        logger.info(f"Enable bct SUCCESS, ret = {ret_code}")
        return ret_code
    return ScriptExitCode.SUCCESS


def get_omf_enable(pfile_name):
    omf_enable = 0
    omf_dest = ''
    encoding = locale.getdefaultlocale()[1]
    pfile_name_lines = read_result_file(pfile_name, encoding=encoding).splitlines()
    for line in pfile_name_lines:
        if "DB_CREATE_FILE_DEST=" in line or "db_create_file_dest=" in line:
            audit_file_dest_line = line.strip()
            omf_dest = audit_file_dest_line.split("#")[0].split("=")[1].replace("'", "")
    if omf_dest:
        omf_enable = 1
    return omf_enable


def get_des_path(pid, restore_params):
    recover_path = restore_params['recover_path']
    if recover_path:
        dst_path = f"{recover_path}\\ctf"
    else:
        additional = restore_params['additional']
        asm_instance = restore_params['asm_sid_name']
        oracle_home = restore_params['oracle_home']
        logfile_info_name = os.path.join(additional, f"logfiles")
        with open(logfile_info_name, 'r') as file:
            first_line = file.readline().strip()
        if len(first_line.split(";")) < 2:
            logger.error(f"Read log file info failed")
            return ""
        origin_path = os.path.dirname(first_line.split(";")[1])
        create_dir(pid, origin_path, asm_instance, oracle_home)
        dst_path = f"{origin_path}\\ctf"
    return dst_path


def oracle_upgrade(restore_params, oracle_is_cdb, ora_preversion):
    pid = restore_params['pid']
    instance_name = restore_params['db_instance']
    db_user = restore_params['db_user']
    db_password = restore_params['db_user_pwd']
    oracle_home = restore_params['oracle_home']
    logger.info(f"Enter function oracle_upgrade, pid:{pid}.")
    tmp_sql = f"{PluginPathConstant.WINDOWS_TMP_PATH}/upgrade_sql{pid}.sql"
    tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/upgrade_sql{pid}.rst"
    upgrade_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/upgrade_rst_{pid}.txt"
    tmp_sql_content = ''
    params = {"is_silence": 1, "db_user": db_user, "db_password": db_password}
    if oracle_is_cdb == 0:
        tmp_sql_content += f"SPOOL {tmp_rst}\n"
        tmp_sql_content += f"ALTER PLUGGABLE DATABASE ALL OPEN UPGRADE FORCE;\n"
        tmp_sql_content += f"SPOOL OFF\n"
        tmp_sql_content += f"exit;\n"
        write_tmp_file(tmp_sql, tmp_sql_content)
        set_db_silence_sql(tmp_sql)
        ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, instance_name)
        if ret_code != ScriptExitCode.SUCCESS:
            with open(tmp_rst, "r") as tmp_rst_stream:
                logger.error(f"Open upgrade pdb database-{instance_name} failed, pid:{pid}, "
                             f"ret_code={ret_code}, error is {tmp_rst_stream.read()}")
            delete_file(tmp_sql)
            delete_file(tmp_rst)
            return RETURN_INVALID
        delete_file(tmp_sql)
        delete_file(tmp_rst)
        logger.info(f"Open upgrade pdb database-{instance_name} success, pid:{pid}.")
    tmp_sql_content = ''
    encoding = locale.getdefaultlocale()[1]
    if int(ora_preversion) > 11:
        upgrade_cmd = f"{oracle_home}\\perl\\bin\\perl catctl.pl -n 4 catupgrd.sqlC > {upgrade_rst}"
        ret, result = execute_windows_cmd(pid, upgrade_cmd.split(), "", cd_path=fr"{oracle_home}\perl\bin\perl")
        if not ret:
            with open(upgrade_rst, "r") as upgrade_rst_stream:
                logger.error(f"Upgrade database {instance_name} failed, pid:{pid}, error is {upgrade_rst_stream}")
            delete_file(upgrade_rst)
            return RETURN_INVALID
    else:
        tmp_sql_content += f"SPOOL {tmp_rst}\n"
        tmp_sql_content += f"spool catupgrade.log\n"
        tmp_sql_content += f"@?/rdbms/admin/catupgrd.sql\n"
        tmp_sql_content += f"SPOOL OFF\n"
        tmp_sql_content += f"exit;\n"
        write_tmp_file(tmp_sql, tmp_sql_content)
        set_db_silence_sql(tmp_sql)
        ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, instance_name)
        if ret_code != ScriptExitCode.SUCCESS:
            logger.error(f"Upgrade database-{instance_name} failed, pid:{pid}, "
                         f"ret_code={ret_code} error is {read_result_file(tmp_rst, encoding=encoding)}")
            delete_file(tmp_sql)
            delete_file(tmp_rst)
    tmp_sql_content = ''
    tmp_sql_content += f"SPOOL {tmp_rst}\n"
    tmp_sql_content += f"startup\n"
    tmp_sql_content += f"@?/rdbms/admin/utlrp.sql\n"
    tmp_sql_content += f"SPOOL OFF\n"
    tmp_sql_content += f"exit;\n"
    write_tmp_file(tmp_sql, tmp_sql_content)
    set_db_silence_sql(tmp_sql)
    ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, instance_name)
    if ret_code != ScriptExitCode.SUCCESS and ret_code != ScriptExitCode.ERROR_ORACLE_DB_ALREADYRUNNING:
        logger.error(f"Check upgrade database-{instance_name} failed, pid:{pid}, error={ret_code}, "
                     f"error is {read_result_file(tmp_rst, encoding=encoding)}")
        return RETURN_INVALID
    delete_file(tmp_sql)
    delete_file(tmp_rst)
    shutdown_database_abort(pid, instance_name, db_user, db_password)
    start_open(pid, instance_name, db_user, db_password)
    logger.info(f"Upgrade database-{instance_name} succ, pid:{pid}.")
    return ScriptExitCode.SUCCESS


def set_rac_pwd_file(pid, spfile_location, db_name, dbpw_file):
    logger.info(f"Enter function set_rac_pwd_file, pid:{pid}.")
    spfile_location_new = spfile_location.split("=")[1].replace("'", "").replace("\"", "")
    spfile_location_new_parts = spfile_location_new.replace("\\", "/").split("/")
    dg_name = spfile_location_new_parts[0]
    dst_pwd_path = f"{dg_name}/{db_name}/PASSWORD/pwd{db_name}"
    delete_pwd_file_cmd = f"cmd /c asmcmd rm -rf {dst_pwd_path}"
    execute_windows_cmd(pid, delete_pwd_file_cmd.split(), "")
    remove_pwd_path_cmd = f"cmd /c srvctl modify database -db {db_name} -pwfile"
    ret, result = execute_windows_cmd(pid, remove_pwd_path_cmd.split(), "")
    if not ret:
        logger.error(f"remove password path failed, pid={pid}")
        return RETURN_INVALID
    # 创建关联密码文件
    creat_pwd_file_cmd = f"cmd /c orapwd input_file={dbpw_file} file={dst_pwd_path} dbuniquename={db_name}"
    ret, result = execute_windows_cmd(pid, creat_pwd_file_cmd.split(), "")
    if not ret:
        logger.error(f"Create Associate password file failed, pid={pid}")
        return RETURN_INVALID
    modify_pwd_file_cmd = f"cmd /c srvctl modify database -db {db_name} -pwfile {dst_pwd_path}"
    ret, result = execute_windows_cmd(pid, modify_pwd_file_cmd.split(), "")
    if not ret:
        logger.error(f"Modify password file failed, pid={pid}")
        return RETURN_INVALID
    return ScriptExitCode.SUCCESS


def modify_pfile_config_param(restore_params, dst_file_path, pfile_name, db_is_cluster):
    pid = restore_params['pid']
    db_name = restore_params['db_name']
    asm_instance = restore_params['asm_sid_name']
    oracle_home = restore_params['oracle_home']
    logger.info(f"Enter function modify_pfile_config_param, pid:{pid}.")
    omf_enable = 0
    omf_dest = ''
    encoding = locale.getdefaultlocale()[1]
    pfile_name_lines = read_result_file(pfile_name, encoding=encoding).splitlines()
    for line in pfile_name_lines:
        if "DB_CREATE_FILE_DEST=" in line or "db_create_file_dest=" in line:
            audit_file_dest_line = line.strip()
            omf_dest = audit_file_dest_line.split("#")[0].split("=")[1].replace("'", "")
    upper_db_name = db_name.upper()
    if omf_dest:
        omf_enable = 1
        omf_dest_dir = os.path.join(dst_file_path, upper_db_name, "datafile")
        create_dir(pid, omf_dest_dir, asm_instance, oracle_home)

    # Modify *.control_files
    if dst_file_path:
        if omf_enable == 1:
            control_file_dir = os.path.join(dst_file_path, upper_db_name, "controlfile")
            create_dir(pid, control_file_dir, asm_instance, oracle_home)
            control_file = os.path.join(dst_file_path, upper_db_name, "controlfile", "controlfile.ctl")
        else:
            control_file = os.path.join(dst_file_path, "controlfile.ctl")
        pfile_name_bak_content = ""
        for line in pfile_name_lines:
            if "CONTROL_FILES=" in line or "control_files=" in line:
                pfile_name_bak_content += f"*.control_files={control_file}\n"
            else:
                pfile_name_bak_content += f"{line}\n"
        write_tmp_file(pfile_name, pfile_name_bak_content)
    else:
        for line in pfile_name_lines:
            if "control_files" in line:
                control_file_dest_list = line.split("#")[0].split("=")[1].split(",")
                for control_file_item in control_file_dest_list:
                    control_file_item = control_file_item.split("'")[1]
                    control_file_item_parts = control_file_item.split("\\")[:-1]
                    control_file_item = "\\".join(control_file_item_parts)
                    create_dir(pid, control_file_item, asm_instance, oracle_home)

    # Modify *.db_create_file_dest
    pfile_name_lines = read_result_file(pfile_name, encoding=encoding).splitlines()
    if omf_enable == 1 and dst_file_path:
        pfile_name_bak_content = ""
        for line in pfile_name_lines:
            if "DB_CREATE_FILE_DEST=" in line or "db_create_file_dest=" in line:
                pfile_name_bak_content += f"*.db_create_file_dest={dst_file_path}\n"
            else:
                pfile_name_bak_content += f"{line}\n"
        write_tmp_file(pfile_name, pfile_name_bak_content)
    elif omf_enable == 1 and not dst_file_path:
        create_dir(pid, omf_dest, asm_instance, oracle_home)

    # Modify *.log_archive_dest_n
    pfile_name_lines = read_result_file(pfile_name, encoding=encoding).splitlines()
    archived_dest_list = []
    for line in pfile_name_lines:
        if "log_archive_dest" in line:
            archived_dest_list.append(line.strip())
    for archived_dest_item in archived_dest_list:
        log_archive_dest = archived_dest_item.split("#")[0].split("=")[0]
        log_archive_dest_parts = log_archive_dest.split(".")
        log_archive_dest = ".".join(log_archive_dest_parts[1:])
        archived_dest_item = archived_dest_item.split("#")[0].split(f"{log_archive_dest}=")[1]
        if archived_dest_item.find("=") != -1:
            archived_dest_item = archived_dest_item.split("'")[1]
            archived_dest_item = archived_dest_item.split("=")[1]
            if archived_dest_item and dst_file_path:
                pfile_name_bak_content = ""
                for line in pfile_name_lines:
                    if f"{log_archive_dest}=" in line:
                        pfile_name_bak_content += f"*.{log_archive_dest}='LOCATION={dst_file_path}'\n"
                    else:
                        pfile_name_bak_content += f"{line}\n"
                write_tmp_file(pfile_name, pfile_name_bak_content)
                break
        else:
            if archived_dest_item and dst_file_path:
                pfile_name_bak_content = ""
                for line in pfile_name_lines:
                    if f"{log_archive_dest}=" in line:
                        pfile_name_bak_content += f"*.{log_archive_dest}={dst_file_path}\n"
                    else:
                        pfile_name_bak_content += f"{line}\n"
                write_tmp_file(pfile_name, pfile_name_bak_content)
                break
        if archived_dest_item:
            create_dir(pid, archived_dest_item, asm_instance, oracle_home)

    # Modify *.db_recovery_file_dest
    pfile_name_lines = read_result_file(pfile_name, encoding=encoding).splitlines()
    fast_recover_dest = ""
    for line in pfile_name_lines:
        if line.find("db_recovery_file_dest=") != -1:
            fast_recover_dest = line.split("=")[1]
    fast_recover_dest_parts = ""
    if len(fast_recover_dest.split("'")) > 1:
        fast_recover_dest_parts = fast_recover_dest.split("'")[1]
    if fast_recover_dest_parts:
        if fast_recover_dest and dst_file_path:
            pfile_name_bak_content = ""
            for line in pfile_name_lines:
                if f"DB_RECOVERY_FILE_DEST=" in line or f"db_recovery_file_dest=" in line:
                    pfile_name_bak_content += f"*.db_recovery_file_dest={dst_file_path}\n"
                else:
                    pfile_name_bak_content += f"{line}\n"
            write_tmp_file(pfile_name, pfile_name_bak_content)
    elif fast_recover_dest:
        create_dir(pid, fast_recover_dest, asm_instance, oracle_home)

    # RAC to Single-Instance
    pfile_name_lines = read_result_file(pfile_name, encoding=encoding).splitlines()
    if db_is_cluster == 0 or db_is_cluster == 2:
        pfile_name_bak_content = ""
        for line in pfile_name_lines:
            if f"CLUSTER_DATABASE" in line or f"cluster_database" in line:
                pfile_name_bak_content += f"*.cluster_database=FALSE\n"
            else:
                pfile_name_bak_content += f"{line}\n"
        write_tmp_file(pfile_name, pfile_name_bak_content)
    return omf_enable


def clear_redo_log_file(pid, db_user, db_user_pwd, db_instance):
    logger.info("Start clear redo log file.")
    tmp_sql = f"{PluginPathConstant.WINDOWS_TMP_PATH}/clear_redo_log_file_{pid}.sql"
    tmp_rst = f"{PluginPathConstant.WINDOWS_TMP_PATH}/clear_redo_log_file_rst_{pid}.rst"
    ret_code = get_online_redo_log_info(pid, db_instance, db_user, db_user_pwd, tmp_rst)
    if ret_code != ScriptExitCode.SUCCESS:
        logger.error(f"Get database online log file info failed, pid:{pid}.")
        delete_file(tmp_rst)
        return ret_code
    # 依次处理每一个redo名称
    encoding = locale.getdefaultlocale()[1]
    content = f"SPOOL {tmp_rst}\n"
    tmp_rst_lines = read_result_file(tmp_rst, encoding=encoding).splitlines()
    for line in tmp_rst_lines:
        if not line or ("rows selected" in line):
            continue
        redo_file = line.split()[0].strip()
        logger.info(f"ALTER DATABASE CLEAR LOGFILE group {redo_file};")
        content += f"ALTER DATABASE CLEAR LOGFILE group {redo_file};\n"
    content += f"SPOOL OFF\n"
    content += "exit;"
    write_tmp_file(tmp_sql, content)
    params = {"is_silence": 1, "db_user": db_user, "db_password": db_user_pwd}
    ret_code = execute_windows_sqlplus_cmd(pid, params, tmp_sql, tmp_rst, db_instance)
    if ret_code != ScriptExitCode.SUCCESS:
        logger.error(
            f"Clear database-{db_instance} redo log file failed, ret=${ret_code}"
            f"error is {read_result_file(tmp_rst, encoding=encoding)}")
        delete_file(tmp_sql)
        delete_file(tmp_rst)
        return ret_code
    logger.info(f"Clear database-${db_instance} redo log file successfully, pid:{pid}.")
    delete_file(tmp_sql)
    delete_file(tmp_rst)
    return ScriptExitCode.SUCCESS
